package ss

import (
	"github.com/sniperHW/kendynet"
	//"github.com/sniperHW/kendynet/socket/stream_socket"
	"sanguo/codec/pb"
	"github.com/golang/protobuf/proto"
	"github.com/sniperHW/kendynet/rpc"
	"fmt"
	"os"
	"time"
	//"sync"
	//"bufio"
	//"io"
	"net"
	//"encoding/binary"
)

const (
	maxPacketSize uint64 = 65535*4
	minSize uint64 = sizeLen + sizeFlag + sizeCmd
)

/*
type Receiver struct {
	ns_msg  	   string
	ns_req         string
	ns_resp        string
	reader        *bufio.Reader
	head           []byte
	payload        []byte
}

func NewReceiver(ns_msg,ns_req,ns_resp string) (*Receiver) {
	receiver := &Receiver{}
	receiver.ns_msg   = ns_msg
	receiver.ns_req   = ns_req
	receiver.ns_resp  = ns_resp
	receiver.head = make([]byte,4)
	return receiver
}

func (this *Receiver) ReceiveAndUnpack(sess kendynet.StreamSession) (interface{},error) {
	if this.reader == nil {
		this.reader = bufio.NewReaderSize(sess.GetUnderConn().(io.Reader),(int)(maxPacketSize))
	}

	var n int
	var err error
	var flag byte
	var cmd  uint16
	var buff []byte
	var errStr string
	var msg proto.Message	

	n,err = this.reader.Read(this.head)
	if err != nil {
		return nil,err
	} else if n != 4{
		return nil,fmt.Errorf("read error")
	}

	payloadSize := binary.BigEndian.Uint32(this.head)

	if uint64(payloadSize) == 0 {
		err = fmt.Errorf("zero payload")
		return nil,err
	}

	totalSize := uint64(payloadSize + sizeLen)

	if totalSize > maxPacketSize {
		err = fmt.Errorf("large packet %d",totalSize)
		return nil,err
	}

	if nil == this.payload || payloadSize > (uint32)(len(this.payload)) {
		this.payload = make([]byte,payloadSize)
	}

	buff = this.payload[:payloadSize]
	n,err = this.reader.Read(buff)
	if err != nil {
		return nil,err
	} else if n != len(buff) {
		return nil,fmt.Errorf("read error")
	}

	reader := kendynet.NewReader(kendynet.NewByteBuffer(buff,len(buff)))

	if flag,err = reader.GetByte(); err != nil {
		return nil,err
	}	
	
	if cmd,err = reader.GetUint16(); err != nil {
		return nil,err
	}
	
	tt := getMsgType(flag)
	if tt == MESSAGE {
		//普通消息
		size := payloadSize - (sizeCmd + sizeFlag)
		if buff,err = reader.GetBytes(uint64(size)); err != nil {
			return nil,err
		}
		if msg,err = pb.Unmarshal(this.ns_msg,uint32(cmd),buff); err != nil {
			return nil,err
		}
		//this.r += totalSize
		return NewMessage(pb.GetNameByID(this.ns_msg,uint32(cmd)),msg),nil				
	} else {
		var seqNO uint64
		if seqNO,err = reader.GetUint64(); err != nil {
			return nil,err
		}

		size := payloadSize - (sizeCmd + sizeFlag + sizeRPCSeqNo)
		if tt == RPCERR {
			//RPC响应错误信息
			if errStr,err = reader.GetString(uint64(size)); err != nil {
				return nil,err
			}
			return &rpc.RPCResponse{Seq:seqNO,Err:fmt.Errorf(errStr)},nil
			//break
		} else if tt == RPCRESP {
			//RPC响应
			if buff,err = reader.GetBytes(uint64(size)); err != nil {
				return nil,err
			}
			if msg,err = pb.Unmarshal(this.ns_resp,uint32(cmd),buff); err != nil {
				return nil,err
			}
			return &rpc.RPCResponse{Seq:seqNO,Ret:msg},nil
		} else if tt == RPCREQ {
			//RPC请求
			if buff,err = reader.GetBytes(uint64(size)); err != nil {
				return nil,err
			}
			if msg,err = pb.Unmarshal(this.ns_req,uint32(cmd),buff); err != nil {
				return nil,err
			}
			return &rpc.RPCRequest{
				Seq : seqNO,
				Method : pb.GetNameByID(this.ns_req,uint32(cmd)),
				NeedResp : getNeedRPCResp(flag),
				Arg : msg,	
			},nil
		} else {
			kendynet.Infof("invaild message type\n")
			os.Exit(0)
		}
	}
	return nil,fmt.Errorf("read error")	

}
*/


type Receiver struct {
	buffer         []byte
	w              uint64
	r              uint64
	ns_msg  	   string
	ns_req         string
	ns_resp        string
	lastRecved     int
	recvCount      int
	unpackCount    int
}

func NewReceiver(ns_msg,ns_req,ns_resp string) (*Receiver) {
	receiver := &Receiver{}
	receiver.ns_msg   = ns_msg
	receiver.ns_req   = ns_req
	receiver.ns_resp  = ns_resp
	receiver.buffer   = make([]byte,maxPacketSize*2)
	return receiver
}

func (this *Receiver) unPack() (interface{},error) {
	var totalSize uint64
	unpackSize := uint64(this.w - this.r)
	if unpackSize >= minSize {
		//var totalSize uint64
		var payload uint32
		var flag byte
		var cmd  uint16
		var err  error
		var buff []byte
		var errStr string
		var msg proto.Message
		reader := kendynet.NewReader(kendynet.NewByteBuffer(this.buffer[this.r:],unpackSize))
		if payload,err = reader.GetUint32(); err != nil {
			return nil,err
		}

		if uint64(payload) == 0 {
			//kendynet.Errorln("r",this.r,"w",this.w,"lastRecved",this.lastRecved,this.buffer[this.r:this.w])
			kendynet.Infoln(this.lastRecved,this.r,this.w,this.buffer[this.r:this.w])
			err = fmt.Errorf("zero payload")
			return nil,err
		}

		totalSize = uint64(payload + sizeLen)

		if totalSize > maxPacketSize {
			kendynet.Infoln(this.recvCount,this.unpackCount,this.lastRecved,this.r,this.w,this.buffer[this.r:this.w])
			err = fmt.Errorf("large packet %d",totalSize)
			return nil,err
		}

		if totalSize <= unpackSize {

			if flag,err = reader.GetByte(); err != nil {
				return nil,err
			}	
			
			if cmd,err = reader.GetUint16(); err != nil {
				return nil,err
			}
			
			tt := getMsgType(flag)
			if tt == MESSAGE {
				//普通消息
				size := payload - (sizeCmd + sizeFlag)
				if buff,err = reader.GetBytes(uint64(size)); err != nil {
					return nil,err
				}
				if msg,err = pb.Unmarshal(this.ns_msg,uint32(cmd),buff); err != nil {
					return nil,err
				}
				this.r += totalSize
				return NewMessage(pb.GetNameByID(this.ns_msg,uint32(cmd)),msg),nil				
			} else {
				var seqNO uint64
				if seqNO,err = reader.GetUint64(); err != nil {
					return nil,err
				}

				size := payload - (sizeCmd + sizeFlag + sizeRPCSeqNo)
				if tt == RPCERR {
					//RPC响应错误信息
					if errStr,err = reader.GetString(uint64(size)); err != nil {
						return nil,err
					}
					this.r += totalSize
					return &rpc.RPCResponse{Seq:seqNO,Err:fmt.Errorf(errStr)},nil
					//break
				} else if tt == RPCRESP {
					//RPC响应
					if buff,err = reader.GetBytes(uint64(size)); err != nil {
						return nil,err
					}
					if msg,err = pb.Unmarshal(this.ns_resp,uint32(cmd),buff); err != nil {
						return nil,err
					}
					this.r += totalSize
					return &rpc.RPCResponse{Seq:seqNO,Ret:msg},nil
				} else if tt == RPCREQ {
					//RPC请求
					if buff,err = reader.GetBytes(uint64(size)); err != nil {
						return nil,err
					}
					if msg,err = pb.Unmarshal(this.ns_req,uint32(cmd),buff); err != nil {
						return nil,err
					}
					this.r += totalSize
					return &rpc.RPCRequest{
						Seq : seqNO,
						Method : pb.GetNameByID(this.ns_req,uint32(cmd)),
						NeedResp : getNeedRPCResp(flag),
						Arg : msg,	
					},nil
				} else {
					kendynet.Infof("invaild message type\n")
					os.Exit(0)
				}
			}
		}
	}
	//if unpackSize > 0 {
	//	fmt.Println("total",totalSize,"unpack",unpackSize,"r",this.r,"w",this.w,"lastRecved",this.lastRecved)
	//}
	return nil,nil
}

func (this *Receiver) check(buff []byte, n int) {
	l := len(buff)
	l = l / 4
	for i:=0;i < l;i++{
		var j int
		for j=0;j<4;j++{
			if buff[i*4+j] != 0xFF {
				break
			}
		}
		if j == 4 {
			kendynet.Infoln(n,buff)
			time.Sleep(time.Second)
			os.Exit(0)
		}
	}
}


func (this *Receiver) ReceiveAndUnpack(sess kendynet.StreamSession) (interface{},error) {
	var msg interface{}
	var err error
	for {
		this.unpackCount++
		msg,err = this.unPack()

		if nil != msg {
			return msg,nil
		} else if err == nil {
			if this.w == this.r {
				this.w = 0
				this.r = 0		
				b := this.buffer[this.w:]
					for k,_ := range(b) {
					b[k] = 0
				}
			} else if uint64(cap(this.buffer)) - this.w < maxPacketSize / 4 {	
				copy(this.buffer,this.buffer[this.r:this.w])
				//kendynet.Infoln("move",this.recvCount,this.unpackCount,this.w-this.r,this.w,this.r,this.lastRecved)
				this.w = this.w - this.r
				this.r = 0		
				b := this.buffer[this.w:]
					for k,_ := range(b) {
					b[k] = 0
				}
			}

			conn := sess.GetUnderConn().(*net.TCPConn)
			n,err := conn.Read(this.buffer[this.w:])
			this.recvCount++

			if n > 0 {
				this.w += uint64(n) //增加待解包数据	
				this.lastRecved = n	
			}
			if err != nil {
				return nil,err
			}
		} else {
			return nil,err
		}
	}
}


func (this *Receiver) TestUnpack(buff []byte) (interface{},error) {
	copy(this.buffer,buff[:])
	this.r = 0
	this.w = uint64(len(buff))
	packet,err := this.unPack()
	return packet,err
}
